package com.andatsoft.laisim.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Typeface;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.support.v4.app.NotificationCompat;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.util.DisplayMetrics;
import android.util.Log;
import android.widget.RemoteViews;

import com.andatsoft.laisim.R;
import com.andatsoft.laisim.activity.MainActivity;
import com.andatsoft.laisim.activity.WelcomeActivity;
import com.andatsoft.laisim.asynctask.ConfigSaverTask;
import com.andatsoft.laisim.audioeffect.AudioEffect;
import com.andatsoft.laisim.audioeffect.AudioEffectManager;
import com.andatsoft.laisim.config.LaisimConfig;
import com.andatsoft.laisim.db.DataBaseAccess;
import com.andatsoft.laisim.entity.Song;
import com.andatsoft.laisim.receiver.LockScreenReceiver;
import com.andatsoft.laisim.theme.ThemeManager;
import com.andatsoft.laisim.utils.Common;
import com.andatsoft.laisim.utils.Utils;
import com.andatsoft.laisim.widget.MediumWidgetProvider;
import com.andatsoft.laisim.widget.SmallWidgetProvider;
import com.andatsoft.laisim.widget.TinyWidgetProvider;

public class PlayerService extends Service implements OnPreparedListener,
		OnCompletionListener, OnErrorListener {
	public static final String NOTIFICATION_RECEIVER = "player.notification.receiver";
	public static final String NOTIFICATION_RECEIVER_DATA = "player.notification.receiver.data";
	public static final String INTENT_SERVICE_COMMAND = "player.intent.command";
	public static final String INTENT_SERVICE_COMMAND_EXTRAS = "player.intent.command.extras";
	public static final String INTENT_PLAYLIST_CHANGED = "player.intent.playlistchanged";
	public static final String INTENT_SETTING_CHANGED = "player.intent.settingchanged";
	public static final String INTENT_SKIN_CHANGED = "player.intent.skinchanged";
	public static final String INTENT_HEADPHONE_PLUGGED = "player.intent.headphoneplugged";
	public static final String INTENT_LOCK_SCREEN_SETTING_CHANGED = "player.intent.lockscreen.changed";

	public static final int SERVICE_COMMAND_MAIN_ACTIVITY = 1;
	public static final int SERVICE_COMMAND_NOTIFICATION_PREV = 2;
	public static final int SERVICE_COMMAND_NOTIFICATION_PLAY_PAUSE = 3;
	public static final int SERVICE_COMMAND_NOTIFICATION_NEXT = 4;
	public static final int SERVICE_COMMAND_NOTIFICATION_CLOSE = 5;
	public static final int SERVICE_COMMAND_WIDGET_TINY_UPDATE = 7;
	public static final int SERVICE_COMMAND_BASE_WIDGET_UPDATE = 6;

	public static int audioSessionId;
	public static boolean isServiceStartedByMainActivity;
	public static boolean isMediaCompelete = false;
	private final int mNotificationId = 6969;
	// public static class CurrentSongInfo
	// {
	// String title;
	// String artist;
	// boolean isPlaying;
	// }

	private final int UPDATE_PLAYED_TIME = 250;
	// private final int CROSS_FADE_TIME = 1000;
	private NotificationManager mNotificationManager;
	private WakeLock mWakeLock;
	private TelephonyManager mTelephonyManager;

	// Player
	private MediaPlayer mMediaPlayer;

	// list of songs
	private List<Song> mSongList;
	// private Playlist mPlaylist;
	private int mCurrentSongIndex;
	private int mTempCurrentSongIndex;
	private int mCurrentSongDuration = 1;
	private int mFadeTime = 1000;

	private boolean mIsSkinReleased = true;

	private DataBaseAccess mDatabase;

	// Settings
	private boolean mIsShuffle;

	public enum RepeatMode {
		NONE, REPEAT_ONE, REPEAT_ALL
	}

	private RepeatMode mRepeatMode = RepeatMode.NONE;
	private boolean mIsSoundEqualizer;
	private boolean mIsSoundBassBooster;
	private boolean mIsSoundFading = true;
	private boolean mIsInFading = false;
	private boolean mIsOutFading = false;
	private float mVolume = 1.0f;
	private int mSavedCurrentDuration = 0;
	private boolean mIsPreparing;
	private float mBalanceLeft;
	private float mBalanceRight;
	// Intent
	private Intent mTimePlayedIntent;
	private Intent mSongIndexIntent;
	private Intent mStopSongIntent;
	private BroadcastReceiver mNotificationReceiver;
	private boolean mIsPlaylistChanged;
	private boolean mIsSkinChanged;
	private boolean mIsNeedUpdateAlbumArt;
	private boolean mIsNeedToChangedSong;
	private boolean mIsAutoPlayByHeadPhonePlugged = true;
	private boolean mIsAutoStopByHeadPhoneUnPlugged = true;

	private BroadcastReceiver mLockScreenBroadcastReceiver;

	private BroadcastReceiver mBroadcastLockScreenChanged = new BroadcastReceiver() {

		@SuppressWarnings("deprecation")
		@Override
		public void onReceive(Context context, Intent intent) {
			if (keyguardLock == null)
				return;
			SharedPreferences sp = getSharedPreferences(
					Common.SP_LOCK_SCREEN_SETTING_NAME, Context.MODE_PRIVATE);
			boolean useLaisimLock = sp.getBoolean(
					Common.SP_LOCK_SCREEN_SETTING_USE_LAISIM_LOCK, true);
			if (useLaisimLock) {
				if (isPlaying()) {
					keyguardLock.disableKeyguard();
				} else {
					keyguardLock.reenableKeyguard();
				}
			} else {
				keyguardLock.reenableKeyguard();
			}
		}
	};
	private BroadcastReceiver mBroadcastSettingChanged = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			SharedPreferences sp = getSharedPreferences(
					Common.SP_AUDIO_SETTING_NAME, Context.MODE_PRIVATE);
			mIsSoundFading = sp.getBoolean(Common.SP_AUDIO_IS_FADE, true);
			mFadeTime = sp.getInt(Common.SP_AUDIO_FADE_TIME, 1000);
		}
	};

	private BroadcastReceiver mBroadcastSkinChanged = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			mIsSkinChanged = true;
		}
	};

	// private BroadcastReceiver mBroadcastHeadPhoneClick = new
	// BroadcastReceiver() {
	//
	// @Override
	// public void onReceive(Context context, Intent intent) {
	// KeyEvent key = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
	// Log.e("key", key.getCharacters());
	// }
	// };

	private BroadcastReceiver mBroadcastHeadPhonePlugged = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			if (intent == null)
				return;
			if (intent.getExtras() == null)
				return;
			SharedPreferences sp = getSharedPreferences(
					Common.SP_HEADPHONES_SETTING_NAME, Context.MODE_PRIVATE);
			mIsAutoPlayByHeadPhonePlugged = sp.getBoolean(
					Common.SP_HEADPHONES_IS_AUTO_PLAY_WHEN_PLUGGED, true);
			mIsAutoStopByHeadPhoneUnPlugged = sp.getBoolean(
					Common.SP_HEADPHONES_IS_AUTO_STOP_WHEN_UNPLUGGED, true);
			int state = intent.getExtras().getInt("state");
			if (state == 1) {
				if (mIsAutoPlayByHeadPhonePlugged) {
					if (!isPlaying())
						play();
				}
			} else {
				if (mIsAutoStopByHeadPhoneUnPlugged) {
					if (isPlaying())
						stop();
				}
			}
		}
	};

	private BroadcastReceiver mBroadcastPlaylistChanged = new BroadcastReceiver() {

		@Override
		public void onReceive(Context c, Intent data) {
			// get the saved playing song
			DataBaseAccess db = DataBaseAccess
					.getInstance(getApplicationContext());
			List<Song> temp = db.getSavedPlayingSong();
			// check if the current song has changed
			boolean needChangeSong = true;
			int songId = -1;
			if (getCurrentSong() != null) {
				songId = getCurrentSong().getId();

				if (mSongList.size() != temp.size()) {
					needChangeSong = true;
				} else {
					for (Song s : temp) {
						if (songId == s.getId()) {
							needChangeSong = false;
							break;
						}
					}
				}
				mSongList.clear();
				mSongList.addAll(temp);
				if (data != null) {
					Bundle bd = data.getExtras();
					if (bd != null) {
						mIsNeedToChangedSong = bd.getBoolean(
								Common.INTENT_DATA_SONG_PLAYING_CHANGED, false);
						if (mIsNeedToChangedSong)
							needChangeSong = true;
					}
				}
			} else {
				mSongList.clear();
				mSongList.addAll(temp);
				needChangeSong = true;
				mIsNeedToChangedSong = true;
			}
			if (needChangeSong) {
				if (mIsNeedToChangedSong) {
					mCurrentSongIndex = 0;
					if (mSongList.size() <= 0) {
						resetLaisim(false);
					} else {
						play(0);
					}
				} else {
					mCurrentSongIndex = getSongIndexById(songId);
				}
			}
			if (mCurrentSongIndex == -1)
				mCurrentSongIndex = 0;
			mTempCurrentSongIndex = mCurrentSongIndex;
			mIsPlaylistChanged = true;
			mIsNeedUpdateAlbumArt = true;
		}
	};

	private Handler mHandle = new Handler();
	// Binder
	private final IBinder mBinder = new LocalBinder();

	public class LocalBinder extends Binder {
		public PlayerService getService() {
			return PlayerService.this;
		}
	}

	@Override
	public IBinder onBind(Intent intent) {
		Log.e("Service", "onbind called");
		return mBinder;
	}

	@SuppressWarnings("deprecation")
	@Override
	public void onCreate() {
		super.onCreate();
		Log.e("Service", "oncreate called");
		int sdk = android.os.Build.VERSION.SDK_INT;
		if (sdk > android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
			Utils.androidOs = Common.ANDROID_OS_JELLY_BEAN_PLUS;
		} else if (sdk > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
			Utils.androidOs = Common.ANDROID_OS_GINGERBREAD_TO_ICS;
		} else {
			Utils.androidOs = Common.ANDROID_OS_GINGERBREAD;
		}
		mSongList = new ArrayList<Song>();
		mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
		mTelephonyManager = (TelephonyManager) getSystemService(Service.TELEPHONY_SERVICE);
		if (mTelephonyManager != null)
			mTelephonyManager.listen(mPhoneStateListener,
					PhoneStateListener.LISTEN_CALL_STATE);
		mMediaPlayer = new MediaPlayer();
		mMediaPlayer.setOnPreparedListener(this);
		mMediaPlayer.setOnCompletionListener(this);
		audioSessionId = mMediaPlayer.getAudioSessionId();

		mTimePlayedIntent = new Intent(Common.INTENT_UPDATE_TIME_PLAYED);
		mSongIndexIntent = new Intent(Common.INTENT_UPDATE_SONG_INFO);
		mStopSongIntent = new Intent(Common.INTENT_STOP_SONG);
		registerReceiver(mBroadcastPlaylistChanged, new IntentFilter(
				INTENT_PLAYLIST_CHANGED));
		registerReceiver(mBroadcastSettingChanged, new IntentFilter(
				INTENT_SETTING_CHANGED));
		registerReceiver(mBroadcastSkinChanged, new IntentFilter(
				INTENT_SKIN_CHANGED));
		registerReceiver(mBroadcastHeadPhonePlugged, new IntentFilter(
				Intent.ACTION_HEADSET_PLUG));
		registerReceiver(mBroadcastLockScreenChanged, new IntentFilter(
				INTENT_LOCK_SCREEN_SETTING_CHANGED));
		IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
		filter.addAction(Intent.ACTION_SCREEN_OFF);

		mLockScreenBroadcastReceiver = new LockScreenReceiver();
		registerReceiver(mLockScreenBroadcastReceiver, filter);
		SharedPreferences sp = getSharedPreferences(Common.SP_CONFIG_NAME,
				Context.MODE_PRIVATE);
		if (!sp.getBoolean(Common.SP_CONFIG_IS_LOADED, true)) {
			mIsStartAlone = true;
			Log.e("Service", "start alone true");
		}
		loadConfig();
		applyPlayerSetting();

		KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
		keyguardLock = km.newKeyguardLock("LaisimLock");
		// registerReceiver(mBroadcastHeadPhoneClick, new IntentFilter(
		// Intent.ACTION_MEDIA_BUTTON));

	}

	private boolean mIsStoppedByPhoneCall;
	private boolean mIsRingHandler;
	private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {

		@Override
		public void onCallStateChanged(int state, String incomingNumber) {
			switch (state) {
			case TelephonyManager.CALL_STATE_IDLE:
				if (mIsStoppedByPhoneCall) {
					mIsStoppedByPhoneCall = false;
					start();
				}
				// Log.d("Callll", "incoming IDLE");
				// resume
				break;
			case TelephonyManager.CALL_STATE_RINGING:
				// the phone is ringing
				if (isPlaying()) {
					mIsRingHandler = true;
					mIsStoppedByPhoneCall = true;
					pause(false);
				}
				// Log.e("Callll", "RINGING :");
				break;

			case TelephonyManager.CALL_STATE_OFFHOOK:
				// when user in call
				if (mIsRingHandler) {
					mIsRingHandler = false;
					break;
				}
				if (isPlaying()) {
					mIsStoppedByPhoneCall = true;
					pause(false);
				}
				// Log.e("Callll", "CALL_STATE_OFFHOOK :");
				break;

			}
			super.onCallStateChanged(state, incomingNumber);
		};
	};

	private boolean mIsStartAlone;
	private boolean mShouldPlayWhenStartAlone;

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// Log.i("LocalService", "Received start id " + startId + ": " +
		// intent);
		if (mSongList == null || mSongList.size() <= 0) {

			mSongList = loadPlayingSongListFromDB();
			if (mSongList.size() < 1)
				setCurrentSongIndex(0);
			preparePlayer();
		}
		if (intent == null)
			return START_STICKY;
		Bundle data = intent.getExtras();
		if (data == null)
			return START_STICKY;
		int cmd = data.getInt(PlayerService.INTENT_SERVICE_COMMAND);
		Log.i("Player Service", "Command " + cmd);

		if (AudioEffectManager.getCurrentAudioEffect() == null) {
			AudioEffectManager.initAudioEffect(audioSessionId);
		}
		if (ThemeManager.getSelectedSkin() == null) {
			ThemeManager.loadSkin(getApplicationContext(),
					ThemeManager.PLAYER_SERVICE);
		}
		switch (cmd) {
		case SERVICE_COMMAND_MAIN_ACTIVITY:
			Log.i("Player Service", "Command " + isServiceStartedByMainActivity
					+ " " + mSongList.size());
			if (isServiceStartedByMainActivity || isPlaying()) {
				sendBroadCastSongInfoData();
				break;
			}
			if (mSongList == null || mSongList.size() <= 0) {
				mSongList = loadPlayingSongListFromDB();
				setCurrentSongIndex(0);
			}
			if (mSongList.size() > 0) {
				preparePlayer();
			}
			// init effect
			AudioEffectManager
					.initAudioEffect(mMediaPlayer.getAudioSessionId());
			isServiceStartedByMainActivity = true;
			int cmdEx = data
					.getInt(PlayerService.INTENT_SERVICE_COMMAND_EXTRAS);
			if (cmdEx != 0) {
				updateWidget(false);
			}
			break;
		case SERVICE_COMMAND_NOTIFICATION_PREV:
			playPrevious();
			break;
		case SERVICE_COMMAND_NOTIFICATION_PLAY_PAUSE:
			Log.i("Player Service", "alone: " + mIsStartAlone);
			if (mIsStartAlone) {
				mShouldPlayWhenStartAlone = true;
				preparePlayer();
			} else {
				if (isPlaying()) {
					pause(false);
					displayNotification(false);
					updateWidget(false);
				} else {
					start();
				}
			}
			break;
		case SERVICE_COMMAND_NOTIFICATION_NEXT:
			playNext();
			break;
		case SERVICE_COMMAND_NOTIFICATION_CLOSE:
			pause(true);
			break;
		case SERVICE_COMMAND_BASE_WIDGET_UPDATE:
			updateWidget(isPlaying());
			break;
		}

		return START_STICKY;
	}

	private void preparePlayer() {
		try {
			mMediaPlayer.reset();
			if (mSongList.size() <= 0
					|| mTempCurrentSongIndex > mSongList.size() - 1)
				return;
			mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
			mMediaPlayer.setDataSource(mSongList.get(mTempCurrentSongIndex)
					.getAddress());
			mIsPreparing = true;
			mMediaPlayer.prepareAsync();
		} catch (IllegalArgumentException e) {

			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (IndexOutOfBoundsException ie) {
			ie.printStackTrace();
		}
	}

	public void sendBroadCastTimePlayedData(int timePlayed) {
		mTimePlayedIntent.putExtra(Common.BROADCAST_SONG_CURRENT_DURATION,
				timePlayed);
		sendBroadcast(mTimePlayedIntent);
	}

	public void sendBroadCastSongInfoData() {
		sendBroadcast(mSongIndexIntent);
	}

	public void updateWidget(boolean playing) {
		if (mSongList.size() <= 0)
			return;
		updateTinyWidget(playing);
		if (mCurrentSongIndex < 0 || mCurrentSongIndex > mSongList.size() - 1)
			return;
		updateSmallWidget(playing);
		updateMediumWidget(playing);
	}

	private void updateTinyWidget(boolean playing) {
		RemoteViews remoteViews = new RemoteViews(getPackageName(),
				R.layout.widget_layout_tiny);
		SharedPreferences sp = getSharedPreferences(
				Common.SP_WIDGET_SETTING_TINY_NAME, Context.MODE_PRIVATE);
		int bgColor = sp.getInt(Common.SP_WIDGET_SETTING_TINY_BG, 0x00000000);
		remoteViews.setInt(R.id.img_bg_widget_tiny, "setBackgroundColor",
				bgColor);
		ComponentName thisWidget = new ComponentName(getApplicationContext(),
				TinyWidgetProvider.class);
		if (playing) {
			remoteViews.setImageViewResource(R.id.widget_tiny_btn_play_pause,
					R.drawable.btn_notification_pause);
		} else {
			remoteViews.setImageViewResource(R.id.widget_tiny_btn_play_pause,
					R.drawable.btn_notification_play);
		}

		// intent for opening player
		Intent i;
		// Log.e("skin realse", "" + mIsSkinReleased);
		if (mIsSkinReleased) {
			i = new Intent(this, WelcomeActivity.class);
			Log.e("displaywid tiny", "" + "wel next");
		} else {
			i = new Intent(this, MainActivity.class);
			Log.e("displaywid tiny", "" + "main next");
		}

		i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
		i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

		PendingIntent pi = PendingIntent.getActivity(this, 0, i,
				Intent.FLAG_ACTIVITY_CLEAR_TOP);
		remoteViews.setOnClickPendingIntent(R.id.widget_tiny_img_album, pi);

		// The intent for play button
		Intent intentPlay = new Intent(this, PlayerService.class);
		intentPlay.putExtra(INTENT_SERVICE_COMMAND,
				SERVICE_COMMAND_NOTIFICATION_PLAY_PAUSE);
		PendingIntent pPlay = PendingIntent.getService(this, 5, intentPlay, 0);
		remoteViews.setOnClickPendingIntent(R.id.widget_tiny_btn_play_pause,
				pPlay);
		AppWidgetManager.getInstance(getApplicationContext()).updateAppWidget(
				thisWidget, remoteViews);
	}

	private Bitmap convertFontToBitmap(int imgW, int h, int othersViewW,
			String text, boolean isBold, boolean isItalic, int color,
			float textSize) {
		Paint paint = new Paint();
		imgW = (int) Utils.convertDpToPixel(imgW, getApplicationContext());
		int width = (int) (getWindowWidth() - imgW - 20 - Utils
				.convertDpToPixel(othersViewW, getApplicationContext()));

		h = (int) Utils.convertDpToPixel(h, getApplicationContext());
		Bitmap myBitmap = Bitmap
				.createBitmap(width, h, Bitmap.Config.ARGB_4444);
		Canvas myCanvas = new Canvas(myBitmap);

		Typeface tp;
		if (isBold && isItalic) {
			tp = Typeface.create(Typeface.SERIF, Typeface.BOLD_ITALIC);
		} else if (isBold) {
			tp = Typeface.create(Typeface.SERIF, Typeface.BOLD);
		} else if (isItalic) {
			tp = Typeface.create(Typeface.SERIF, Typeface.ITALIC);
		} else {
			tp = Typeface.DEFAULT;
		}
		paint.setTypeface(tp);
		paint.setAntiAlias(true);
		paint.setSubpixelText(true);
		paint.setStyle(Paint.Style.FILL);
		paint.setColor(color);
		paint.setTextSize(convertTextSize(textSize));
		paint.setTextAlign(Align.LEFT);
		TextPaint tpaint = new TextPaint();
		tpaint.setTextSize(textSize * 1.5f);
		CharSequence cs = TextUtils.ellipsize(text, tpaint, width,
				TruncateAt.MARQUEE);
		myCanvas.drawText(cs, 0, cs.length(), 0, (h + 15) / 2, paint);
		return myBitmap;
	}

	private float convertTextSize(float dpVal) {
		return getApplicationContext().getResources().getDisplayMetrics().densityDpi
				* dpVal / 160;
	}

	private float getWindowWidth() {
		DisplayMetrics metrics = getApplicationContext().getResources()
				.getDisplayMetrics();
		return metrics.widthPixels;
	}

	private void updateSmallWidget(boolean playing) {
		RemoteViews remoteViews = new RemoteViews(getPackageName(),
				R.layout.widget_layout_small);
		SharedPreferences sp = getSharedPreferences(
				Common.SP_WIDGET_SETTING_SMALL_NAME, Context.MODE_PRIVATE);
		int mSmallBgColor = sp.getInt(Common.SP_WIDGET_SETTING_SMALL_BG,
				0x00ffffff);
		remoteViews.setInt(R.id.img_bg_widget_small, "setBackgroundColor",
				mSmallBgColor);
		int mSmallTitleColor = sp.getInt(
				Common.SP_WIDGET_SETTING_SMALL_TITLE_COLOR, 0xff000000);
		boolean mSmallTitleBold = sp.getBoolean(
				Common.SP_WIDGET_SETTING_SMALL_TITLE_IS_BOLD, false);

		boolean mSmallTitleItalic = sp.getBoolean(
				Common.SP_WIDGET_SETTING_SMALL_TITLE_IS_ITALIC, false);

		ComponentName thisWidget = new ComponentName(getApplicationContext(),
				SmallWidgetProvider.class);

		Song s = mSongList.get(mCurrentSongIndex);
		if (s == null)
			return;
		// remoteViews.setTextViewText(R.id.widget_small_tv_title,
		// s.getTitle());

		remoteViews.setImageViewBitmap(
				R.id.widget_small_img_title,
				convertFontToBitmap(50, 50, 100, s.getTitle(), mSmallTitleBold,
						mSmallTitleItalic, mSmallTitleColor, 18f));
		remoteViews.setImageViewResource(R.id.widget_small_btn_next,
				R.drawable.btn_notification_next);
		if (playing) {
			remoteViews.setImageViewResource(R.id.widget_small_btn_play_pause,
					R.drawable.btn_notification_pause);
		} else {
			remoteViews.setImageViewResource(R.id.widget_small_btn_play_pause,
					R.drawable.btn_notification_play);
		}

		// intent for opening player
		Intent i;
		// Log.e("skin realse", "" + mIsSkinReleased);
		if (mIsSkinReleased) {
			i = new Intent(this, WelcomeActivity.class);
			Log.e("displaywid small", "" + "wel next");
		} else {
			i = new Intent(this, MainActivity.class);
			Log.e("displaywid small", "" + "main next");
		}

		i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
		i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

		PendingIntent pi = PendingIntent.getActivity(this, 0, i,
				Intent.FLAG_ACTIVITY_CLEAR_TOP);
		remoteViews.setOnClickPendingIntent(R.id.widget_small_img_album, pi);
		remoteViews.setOnClickPendingIntent(R.id.widget_small_img_title, pi);

		// The intent for play button
		Intent intentPlay = new Intent(this, PlayerService.class);
		intentPlay.putExtra(INTENT_SERVICE_COMMAND,
				SERVICE_COMMAND_NOTIFICATION_PLAY_PAUSE);
		PendingIntent pPlay = PendingIntent.getService(this, 5, intentPlay, 0);
		remoteViews.setOnClickPendingIntent(R.id.widget_small_btn_play_pause,
				pPlay);
		// The intent for next button
		Intent intentNext = new Intent(this, PlayerService.class);
		intentNext.putExtra(INTENT_SERVICE_COMMAND,
				SERVICE_COMMAND_NOTIFICATION_NEXT);
		PendingIntent pNext = PendingIntent.getService(this, 12, intentNext, 0);
		remoteViews.setOnClickPendingIntent(R.id.widget_small_btn_next, pNext);
		AppWidgetManager.getInstance(getApplicationContext()).updateAppWidget(
				thisWidget, remoteViews);
	}

	private void updateMediumWidget(boolean playing) {
		RemoteViews remoteViews = new RemoteViews(getPackageName(),
				R.layout.widget_layout_medium);
		SharedPreferences sp = getSharedPreferences(
				Common.SP_WIDGET_SETTING_MEDIUM_NAME, Context.MODE_PRIVATE);
		int mMediumBgColor = sp.getInt(Common.SP_WIDGET_SETTING_MEDIUM_BG,
				0x00ffffff);
		remoteViews.setInt(R.id.img_bg_widget_medium, "setBackgroundColor",
				mMediumBgColor);
		int mMediumTitleColor = sp.getInt(
				Common.SP_WIDGET_SETTING_MEDIUM_TITLE_COLOR, 0xff000000);
		boolean mMediumTitleBold = sp.getBoolean(
				Common.SP_WIDGET_SETTING_MEDIUM_TITLE_IS_BOLD, false);
		boolean mMediumTitleItalic = sp.getBoolean(
				Common.SP_WIDGET_SETTING_MEDIUM_TITLE_IS_ITALIC, false);
		int mMediumOthersColor = sp.getInt(
				Common.SP_WIDGET_SETTING_MEDIUM_OTHERS_COLOR, 0xff000000);
		boolean mMediumOthersBold = sp.getBoolean(
				Common.SP_WIDGET_SETTING_MEDIUM_OTHERS_IS_BOLD, false);
		boolean mMediumOthersItalic = sp.getBoolean(
				Common.SP_WIDGET_SETTING_MEDIUM_OTHERS_IS_ITALIC, false);

		ComponentName thisWidget = new ComponentName(getApplicationContext(),
				MediumWidgetProvider.class);
		if (mCurrentSongIndex < 0 || mCurrentSongIndex >= mSongList.size())
			return;
		Song s = mSongList.get(mCurrentSongIndex);
		if (s == null)
			return;
		// remoteViews.setTextViewText(R.id.widget_medium_tv_title,
		// s.getTitle());
		// remoteViews
		// .setTextViewText(R.id.widget_medium_tv_artist, s.getArtist());
		//
		remoteViews.setImageViewBitmap(
				R.id.widget_medium_img_title,
				convertFontToBitmap(100, 25, 0, s.getTitle(), mMediumTitleBold,
						mMediumTitleItalic, mMediumTitleColor, 20f));

		remoteViews.setImageViewBitmap(
				R.id.widget_medium_img_others,
				convertFontToBitmap(100, 25, 0, s.getArtist(),
						mMediumOthersBold, mMediumOthersItalic,
						mMediumOthersColor, 18f));
		remoteViews.setImageViewBitmap(
				R.id.widget_medium_img_index,
				convertFontToBitmap(100, 50, 0, mCurrentSongIndex + "/"
						+ mSongList.size(), mMediumOthersBold,
						mMediumOthersItalic, mMediumOthersColor, 35f));

		remoteViews.setImageViewResource(R.id.widget_medium_btn_next,
				R.drawable.btn_notification_next);
		remoteViews.setImageViewResource(R.id.widget_medium_btn_prev,
				R.drawable.btn_notification_prev);
		if (ThemeManager.getSelectedSkin() == null) {
			remoteViews.setImageViewResource(R.id.widget_medium_img_album,
					R.drawable.laisim_icon);
		} else {
			remoteViews.setImageViewBitmap(R.id.widget_medium_img_album, Utils
					.scaleDownBitmap(
							s.extractAlbumArt(getApplicationContext()), 100,
							getApplicationContext()));
		}
		if (playing) {
			remoteViews.setImageViewResource(R.id.widget_medium_btn_play_pause,
					R.drawable.btn_notification_pause);
		} else {
			remoteViews.setImageViewResource(R.id.widget_medium_btn_play_pause,
					R.drawable.btn_notification_play);
		}
		// intent for opening player
		Intent i;
		// Log.e("skin realse", "" + mIsSkinReleased);
		if (mIsSkinReleased) {
			i = new Intent(this, WelcomeActivity.class);
			Log.e("displaywid medium", "" + "wel next");
		} else {
			i = new Intent(this, MainActivity.class);
			Log.e("displaywid medium", "" + "main next");
		}

		i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
		i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

		PendingIntent pi = PendingIntent.getActivity(this, 0, i,
				Intent.FLAG_ACTIVITY_CLEAR_TOP);
		remoteViews.setOnClickPendingIntent(R.id.widget_medium_img_album, pi);
		remoteViews.setOnClickPendingIntent(R.id.widget_layout_title, pi);

		// The intent for play button
		Intent intentPlay = new Intent(this, PlayerService.class);
		intentPlay.putExtra(INTENT_SERVICE_COMMAND,
				SERVICE_COMMAND_NOTIFICATION_PLAY_PAUSE);
		PendingIntent pPlay = PendingIntent.getService(this, 5, intentPlay, 0);
		remoteViews.setOnClickPendingIntent(R.id.widget_medium_btn_play_pause,
				pPlay);
		// The intent for next button
		Intent intentNext = new Intent(this, PlayerService.class);
		intentNext.putExtra(INTENT_SERVICE_COMMAND,
				SERVICE_COMMAND_NOTIFICATION_NEXT);
		PendingIntent pNext = PendingIntent.getService(this, 12, intentNext, 0);
		remoteViews.setOnClickPendingIntent(R.id.widget_medium_btn_next, pNext);
		// The intent for prev button
		Intent intentPrev = new Intent(this, PlayerService.class);
		intentPrev.putExtra(INTENT_SERVICE_COMMAND,
				SERVICE_COMMAND_NOTIFICATION_PREV);
		PendingIntent pPrev = PendingIntent.getService(this, 14, intentPrev, 0);
		remoteViews.setOnClickPendingIntent(R.id.widget_medium_btn_prev, pPrev);

		AppWidgetManager.getInstance(getApplicationContext()).updateAppWidget(
				thisWidget, remoteViews);
	}

	public void displayNotification(boolean playing) {
		// int sdk = android.os.Build.VERSION.SDK_INT;
		if (Utils.androidOs > Common.ANDROID_OS_GINGERBREAD_TO_ICS) {
			displayJellyBeanPlusNotification(playing);
		} else if (Utils.androidOs > Common.ANDROID_OS_GINGERBREAD) {
			displayICSNotification(playing);
		} else {
			displayGingerBreadNotification();
		}
	}

	private RemoteViews createJBPlusViews(boolean playing) {
		RemoteViews notificationView = new RemoteViews(getPackageName(),
				R.layout.notification_jb_plus_layout);

		// The intent for play button
		Intent intentPlay = new Intent(this, PlayerService.class);
		intentPlay.putExtra(INTENT_SERVICE_COMMAND,
				SERVICE_COMMAND_NOTIFICATION_PLAY_PAUSE);
		PendingIntent pPlay = PendingIntent.getService(this, 5, intentPlay, 0);
		notificationView.setOnClickPendingIntent(
				R.id.notification_jb_btn_play_pause, pPlay);

		// The intent for prev button
		Intent intentPrev = new Intent(this, PlayerService.class);
		intentPrev.putExtra(INTENT_SERVICE_COMMAND,
				SERVICE_COMMAND_NOTIFICATION_PREV);
		PendingIntent pPrev = PendingIntent.getService(this, 6, intentPrev, 0);
		notificationView.setOnClickPendingIntent(R.id.notification_jb_btn_prev,
				pPrev);

		// The intent for next button
		Intent intentNext = new Intent(this, PlayerService.class);
		intentNext.putExtra(INTENT_SERVICE_COMMAND,
				SERVICE_COMMAND_NOTIFICATION_NEXT);
		PendingIntent pNext = PendingIntent.getService(this, 8, intentNext, 0);
		notificationView.setOnClickPendingIntent(R.id.notification_jb_btn_next,
				pNext);

		// The intent for close button
		Intent intentClose = new Intent(this, PlayerService.class);
		intentClose.putExtra(INTENT_SERVICE_COMMAND,
				SERVICE_COMMAND_NOTIFICATION_CLOSE);
		PendingIntent pClose = PendingIntent.getService(this, 10, intentClose,
				0);
		notificationView.setOnClickPendingIntent(
				R.id.notification_jb_btn_close, pClose);

		if (mCurrentSongIndex < 0 || mCurrentSongIndex > mSongList.size() - 1)
			return notificationView;
		Song s = mSongList.get(mCurrentSongIndex);
		notificationView.setTextViewText(R.id.notification_jb_title,
				s.getTitle());
		notificationView.setTextViewText(R.id.notification_jb_artist,
				s.getAlbum());
		if (ThemeManager.getSelectedSkin() == null) {
			notificationView.setImageViewResource(
					R.id.notification_jb_img_album, R.drawable.laisim_icon);
		} else {
			notificationView.setImageViewBitmap(R.id.notification_jb_img_album,
					Utils.scaleDownBitmap(
							s.extractAlbumArt(getApplicationContext()), 100,
							getApplicationContext()));
		}

		// mHan.post(mR);
		notificationView.setImageViewResource(R.id.notification_jb_btn_next,
				R.drawable.btn_notification_next);
		notificationView.setImageViewResource(R.id.notification_jb_btn_prev,
				R.drawable.btn_notification_prev);
		if (playing) {
			notificationView.setImageViewResource(
					R.id.notification_jb_btn_play_pause,
					R.drawable.btn_notification_pause);
		} else {
			notificationView.setImageViewResource(
					R.id.notification_jb_btn_play_pause,
					R.drawable.btn_notification_play);
		}
		notificationView.setImageViewResource(R.id.notification_jb_btn_close,
				R.drawable.btn_notification_close);
		return notificationView;
	}

	@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
	private void displayJellyBeanPlusNotification(boolean playing) {
		// the intent to open activity when clicked
		// however if the skin is null, the Welcome activity must call first
		Intent i;
		// Log.e("skin realse", "" + mIsSkinReleased);
		if (mIsSkinReleased) {
			i = new Intent(this, WelcomeActivity.class);
		} else {
			i = new Intent(this, MainActivity.class);
		}

		i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
		i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
		PendingIntent pi = PendingIntent.getActivity(this, 0, i,
				Intent.FLAG_ACTIVITY_CLEAR_TOP);
		NotificationCompat.Builder builder = new NotificationCompat.Builder(
				getApplicationContext());
		builder.setSmallIcon(R.drawable.laisim_icon);
		builder.setOngoing(true);
		Notification notification = builder.build();
		BitmapFactory.decodeResource(getResources(), R.drawable.bg_shadow);
		notification.bigContentView = createJBPlusViews(playing);
		notification.contentView = createICSViews(playing);
		// notification.contentView = notificationView;
		notification.contentIntent = pi;
		notification.priority = NotificationCompat.PRIORITY_MAX;
		mNotificationManager.notify(mNotificationId, notification);
		startForeground(mNotificationId, notification);
	}

	private RemoteViews createICSViews(boolean playing) {
		RemoteViews notificationView = new RemoteViews(getPackageName(),
				R.layout.notification_layout);

		// The intent for play button
		Intent intentPlay = new Intent(this, PlayerService.class);
		intentPlay.putExtra(INTENT_SERVICE_COMMAND,
				SERVICE_COMMAND_NOTIFICATION_PLAY_PAUSE);
		PendingIntent pPlay = PendingIntent.getService(this, 5, intentPlay, 0);
		notificationView.setOnClickPendingIntent(
				R.id.notification_btn_play_pause, pPlay);

		// The intent for close button
		Intent intentClose = new Intent(this, PlayerService.class);
		intentClose.putExtra(INTENT_SERVICE_COMMAND,
				SERVICE_COMMAND_NOTIFICATION_CLOSE);
		PendingIntent pClose = PendingIntent.getService(this, 10, intentClose,
				0);
		notificationView.setOnClickPendingIntent(R.id.notification_btn_close,
				pClose);
		if (mCurrentSongIndex < 0 || mCurrentSongIndex > mSongList.size() - 1)
			return notificationView;
		Song s = mSongList.get(mCurrentSongIndex);

		notificationView.setTextViewText(R.id.notification_title, s.getTitle());
		notificationView.setTextViewText(R.id.notification_artist,
				s.getArtist());
		if (ThemeManager.getSelectedSkin() == null) {
			notificationView.setImageViewResource(R.id.notification_img_album,
					R.drawable.laisim_icon);
		} else {
			notificationView.setImageViewBitmap(R.id.notification_img_album,
					Utils.scaleDownBitmap(
							s.extractAlbumArt(getApplicationContext()), 100,
							getApplicationContext()));
		}
		if (playing) {
			notificationView.setImageViewResource(
					R.id.notification_btn_play_pause,
					R.drawable.btn_notification_pause);
		} else {
			notificationView.setImageViewResource(
					R.id.notification_btn_play_pause,
					R.drawable.btn_notification_play);
		}
		notificationView.setImageViewResource(R.id.notification_btn_close,
				R.drawable.btn_notification_close);
		return notificationView;
	}

	private void displayICSNotification(boolean playing) {
		// the intent to open activity when clicked
		Intent i;
		if (mIsSkinReleased) {
			i = new Intent(this, WelcomeActivity.class);

		} else {
			i = new Intent(this, MainActivity.class);
		}
		i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
		i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

		PendingIntent pi = PendingIntent.getActivity(this, 0, i,
				Intent.FLAG_ACTIVITY_CLEAR_TOP);
		NotificationCompat.Builder builder = new NotificationCompat.Builder(
				getApplicationContext());
		builder.setSmallIcon(R.drawable.laisim_icon);
		builder.setOngoing(true);
		Notification notification = builder.build();
		notification.contentView = createICSViews(playing);
		notification.contentIntent = pi;
		mNotificationManager.notify(mNotificationId, notification);
		startForeground(mNotificationId, notification);
	}

	private void displayGingerBreadNotification() {
		RemoteViews notificationView = new RemoteViews(getPackageName(),
				R.layout.notification_ginger_layout);
		// the intent to open activity when clicked
		Intent i;
		if (mIsSkinReleased) {
			i = new Intent(this, WelcomeActivity.class);
		} else {
			i = new Intent(this, MainActivity.class);
		}
		i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
		i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

		PendingIntent pi = PendingIntent.getActivity(this, 0, i,
				Intent.FLAG_ACTIVITY_NEW_TASK);
		if (mCurrentSongIndex < 0 || mCurrentSongIndex > mSongList.size() - 1)
			return;
		Song s = mSongList.get(mCurrentSongIndex);
		NotificationCompat.Builder builder = new NotificationCompat.Builder(
				getApplicationContext());
		builder.setSmallIcon(R.drawable.laisim_icon);
		notificationView.setTextViewText(R.id.notification_gb_title,
				s.getTitle());
		notificationView.setTextViewText(R.id.notification_gb_artist,
				s.getArtist());

		notificationView.setImageViewResource(R.id.notification_gb_img_album,
				R.drawable.bg_shadow);

		builder.setOngoing(true);
		Notification notification = builder.build();
		notification.contentView = notificationView;
		notification.contentIntent = pi;
		mNotificationManager.notify(mNotificationId, notification);
		startForeground(mNotificationId, notification);
	}

	private Runnable updateUIRunnable = new Runnable() {

		@Override
		public void run() {
			if (isPlaying()) {
				sendBroadCastTimePlayedData(mMediaPlayer.getCurrentPosition());
				mHandle.postDelayed(updateUIRunnable, UPDATE_PLAYED_TIME);
			}

		}
	};

	@Override
	public void onCompletion(MediaPlayer mp) {
		// Log.d("Service", "onComplete");
		isMediaCompelete = true;
		displayNotification(false);
		PowerManager pm = ((PowerManager) getApplicationContext()
				.getSystemService(Context.POWER_SERVICE));
		if (!pm.isScreenOn()) {
			mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
					"PlayerWakeLock");
			mWakeLock.acquire();
			// Log.e("Wake lock", "wake lock is accquire");
		}
		switch (mRepeatMode) {
		case NONE:
			if (mIsShuffle) {
				int randIndex = 0;
				if (mSongList.size() > 1) {
					randIndex = new Random().nextInt(mSongList.size() - 1);
				}
				play(randIndex);
			} else {
				mCurrentSongIndex++;
				if (mCurrentSongIndex >= mSongList.size()) {
					mCurrentSongIndex = mSongList.size() - 1;
					sendBroadcast(mStopSongIntent);
					mNotificationManager.cancelAll();
					updateWidget(false);
				} else {
					playNext();
				}
			}

			break;
		case REPEAT_ONE:
			if (mIsShuffle)
				mIsShuffle = false;
			play();
			break;
		case REPEAT_ALL:
			if (mIsShuffle)
				mIsShuffle = false;
			playNext();
			break;
		}

	}

	// Increase the volumn...
	private Timer mFadeInTimer;

	public boolean fadeIn() {
		if (mIsInFading) {
			return false;
		}
		mIsInFading = true;
		// final float curVo = mVolume;
		// mVolume = 0;
		// mMediaPlayer.setVolume(mVolume, mVolume);

		mFadeInTimer = new Timer();
		TimerTask task = new TimerTask() {
			float curVo = 0.0f;

			@Override
			public void run() {
				curVo += mVolume * 10f / (mFadeTime);
				if (curVo >= mVolume) {
					// re update balance effect
					mMediaPlayer.setVolume(mBalanceLeft, mBalanceRight);
					curVo = mVolume;
					mFadeInTimer.cancel();
					mFadeInTimer.purge();
					mIsInFading = false;
					sendBroadcast(mStopSongIntent);
				} else {
					mMediaPlayer.setVolume(curVo, curVo);
				}
			}
		};
		if (mIsOutFading) {// Fading
			mFadeOutTimer.cancel();
			mFadeOutTimer.purge();
			mIsOutFading = false;
		}
		mMediaPlayer.setVolume(0, 0);
		mMediaPlayer.start();
		mFadeInTimer.schedule(task, 0, 10);
		return true;

	}

	// Decrease the volumn...
	private Timer mFadeOutTimer;

	public boolean fadeOut(final boolean playAfter) {
		if (mIsOutFading) {
			return false;
		}
		mIsOutFading = true;
		// final float curVo = mVolume;
		mFadeOutTimer = new Timer();
		TimerTask task = new TimerTask() {
			float curVo = mVolume;

			@Override
			public void run() {
				curVo -= mVolume * 10f / (mFadeTime);
				if (curVo <= 0) {
					curVo = mVolume;
					if (mMediaPlayer.isPlaying()) {
						mMediaPlayer.pause();
						sendBroadcast(mStopSongIntent);
					}
					if (playAfter) {
						play();
					}
					mFadeOutTimer.cancel();
					mFadeOutTimer.purge();
					mIsOutFading = false;
				}
				mMediaPlayer.setVolume(curVo, curVo);
			}
		};
		if (mIsInFading) {// Fading
			mFadeInTimer.cancel();
			mFadeInTimer.purge();
			mMediaPlayer.setVolume(mVolume, mVolume);
			mIsInFading = false;
		}
		mFadeOutTimer.schedule(task, 0, 10);
		return true;

	}

	@Override
	public void onPrepared(MediaPlayer mp) {
		if (mMediaPlayer == null)
			return;
		isMediaCompelete = false;
		// load effect
		AudioEffectManager.loadEffect(getApplicationContext(), getCurrentSong()
				.getEffectId());
		// update volumn and balance
		AudioEffect ae = AudioEffectManager.getCurrentAudioEffect();
		if (ae == null)
			return;
		mMediaPlayer.setVolume(ae.getVolume(), ae.getVolume());
		if (ae.getBalance() <= 50) {
			// balance to left, so we need to reduce volume on
			// right
			mBalanceLeft = 1.0f;
			mBalanceRight = (float) (ae.getBalance() * 2) / 100;

		} else {
			// right
			// balance to right, so we need to reduce volume on
			// left
			mBalanceRight = 1.0f;
			mBalanceLeft = (float) ((100 - ae.getBalance()) * 2) / 100;
		}
		mMediaPlayer.setVolume(mBalanceLeft, mBalanceRight);

		if (mIsPreparing) {
			mMediaPlayer.seekTo(mSavedCurrentDuration);
			mIsPreparing = false;
			if (mIsStartAlone) {
				mIsStartAlone = false;
				if (mShouldPlayWhenStartAlone) {
					mShouldPlayWhenStartAlone = false;
					mp.start();
					displayNotification(true);
					updateWidget(true);
					saveLockScreenSetting(true);
				}
			}
		} else {
			if (mIsSoundFading) {
				fadeIn();
			} else {
				mp.start();
			}
			displayNotification(true);
			updateWidget(true);
			saveLockScreenSetting(true);
		}
		if (mWakeLock != null) {
			if (mWakeLock.isHeld())
				mWakeLock.release();
		}
		audioSessionId = mMediaPlayer.getAudioSessionId();
		sendBroadcast(mStopSongIntent);
		mCurrentSongDuration = mMediaPlayer.getDuration();
		sendBroadCastSongInfoData();
		mHandle.post(updateUIRunnable);
	}

	public void play() {
		mMediaPlayer.reset();
		try {
			if (mSongList.size() <= 0)
				return;
			if (mTempCurrentSongIndex < 0)
				return;
			mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
			mMediaPlayer.setDataSource(mSongList.get(mTempCurrentSongIndex)
					.getAddress());
			mMediaPlayer.prepareAsync();
			mCurrentSongIndex = mTempCurrentSongIndex;
			if (getCurrentSong() != null)
				getCurrentSong().updatePlayedTime();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void play(int index) {
		mTempCurrentSongIndex = index;
		mIsPreparing = false;
		if (mIsSoundFading) {
			fadeOut(true);
		} else {
			play();
		}
	}

	public void playBySongId(int songId) {
		mTempCurrentSongIndex = getSongIndexById(songId);
		if (mIsSoundFading) {
			fadeOut(true);
		}
	}

	public void stop() {
		if (mIsSoundFading)
			fadeOut(false);
		mMediaPlayer.stop();
		saveLockScreenSetting(false);
		mHandle.removeCallbacks(updateUIRunnable);
		sendBroadcast(mStopSongIntent);
		stopForeground(true);
		mNotificationManager.cancelAll();
		updateWidget(false);
	}

	public void pause(boolean cancelNoti) {
		if (mIsSoundFading) {
			fadeOut(false);
		} else {
			mMediaPlayer.pause();
			sendBroadcast(mStopSongIntent);
		}
		saveLockScreenSetting(false);
		mHandle.removeCallbacks(updateUIRunnable);
		if (cancelNoti) {
			stopForeground(true);
			mNotificationManager.cancelAll();
		}

		updateWidget(false);
	}

	public void start() {
		if (mIsSoundFading) {
			fadeIn();
		} else {
			mMediaPlayer.start();
			sendBroadcast(mStopSongIntent);
		}
		saveLockScreenSetting(true);
		mHandle.post(updateUIRunnable);
		displayNotification(true);
		updateWidget(true);
	}

	public void playNext() {
		if (mIsShuffle) {
			int randIndex = 0;
			if (mSongList.size() > 1) {
				randIndex = new Random().nextInt(mSongList.size() - 1);
			}
			mTempCurrentSongIndex = randIndex;
		} else {
			mTempCurrentSongIndex++;
		}
		if (mTempCurrentSongIndex > mSongList.size() - 1)
			mTempCurrentSongIndex = 0;
		if (mIsSoundFading) {
			fadeOut(true);
		} else {
			play();
		}

	}

	public void playPrevious() {
		if (mIsShuffle) {
			int randIndex = 0;
			if (mSongList.size() > 1) {
				randIndex = new Random().nextInt(mSongList.size() - 1);
			}
			mTempCurrentSongIndex = randIndex;
		} else {
			mTempCurrentSongIndex--;
		}
		if (mTempCurrentSongIndex < 0)
			mTempCurrentSongIndex = 0;
		if (mIsSoundFading) {
			fadeOut(true);
		} else {
			play();
		}
	}

	public void playForward(int time) {
		if (isPlaying()) {
			int dur = mMediaPlayer.getCurrentPosition();
			mMediaPlayer.seekTo(dur + time);
		}
	}

	public void playBackward(int time) {
		if (isPlaying()) {
			int dur = mMediaPlayer.getCurrentPosition();
			mMediaPlayer.seekTo(dur - time);
		}

	}

	public void playTo(int pos) {
		mMediaPlayer.seekTo(pos);
		// if (isPlaying()) {
		// // int dur = mMediaPlayer.getCurrentPosition();
		// //mMediaPlayer.seekTo(pos);
		// }
	}

	public void resetLaisim(boolean stopService) {
		mMediaPlayer.reset();
		mCurrentSongIndex = -1;
		mCurrentSongDuration = 0;
		mSongList.clear();
		mTempCurrentSongIndex = -1;
		mNotificationManager.cancelAll();
		updateWidget(false);
		mHandle.removeCallbacks(updateUIRunnable);
		sendBroadCastSongInfoData();
		isServiceStartedByMainActivity = false;
		LaisimConfig.currentDuration = 0;
		LaisimConfig.playingSongId = -1;
		LaisimConfig.playingSongIndex = 0;

		new ConfigSaverTask(getApplicationContext()).execute();
		if (stopService)
			stopSelf();
	}

	public void updateSongWhenRemove(int index) {
		mTempCurrentSongIndex = index;
		mCurrentSongIndex = mTempCurrentSongIndex;
		preparePlayer();
	}

	public boolean isPlaying() {
		try {
			return mMediaPlayer.isPlaying();
		} catch (IllegalStateException ise) {
			ise.printStackTrace();
			return false;
		}
	}

	public boolean isPlaylistChanged() {
		boolean changed = mIsPlaylistChanged;
		mIsPlaylistChanged = false;
		return changed;
	}

	public boolean isSongChanged() {
		boolean changed = mIsNeedToChangedSong;
		mIsNeedToChangedSong = false;
		return changed;
	}

	public boolean isFading() {
		return mIsInFading || mIsOutFading;
	}

	public void resetAndPlay(int index) {
		try {
			mMediaPlayer.reset();
		} catch (IllegalStateException ie) {
			ie.printStackTrace();
		}
		mCurrentSongIndex = index;
		mTempCurrentSongIndex = index;
		preparePlayer();
		mIsPreparing = false;
	}

	public void resetLaisimWhenScanSong() {
		mMediaPlayer.reset();
		mCurrentSongIndex = 0;
		mTempCurrentSongIndex = 0;
		mSongList.clear();
		mCurrentSongDuration = 0;
		mNotificationManager.cancelAll();
	}

	public void setVolume(float left, float right) {
		mMediaPlayer.setVolume(left, right);
	}

	// /////////////////////////////////////////////////////
	//
	// get value
	//
	// /////////////////////////////////////////////////
	public void setPlaylist(List<Song> songs) {
		mSongList.clear();
		mSongList.addAll(songs);
		mIsNeedUpdateAlbumArt = true;
	}

	public List<Song> getSongList() {
		return mSongList;
	}

	public void notifyPlaylistChanged() {
		mIsPlaylistChanged = true;
	}

	public Song getCurrentSong() {
		if (mSongList == null || mSongList.size() <= 0)
			return null;
		if (mTempCurrentSongIndex < 0
				|| mTempCurrentSongIndex > mSongList.size() - 1)
			return null;
		return mSongList.get(mTempCurrentSongIndex);
		// song.updateSongInfo(getApplicationContext());
		// return song;
	}

	// public int getRealSongIndex()
	// {
	//
	// }

	private int getSongIndexById(int id) {
		for (int i = 0; i < mSongList.size(); i++) {
			if (id == mSongList.get(i).getId())
				return i;
		}
		return -1;
	}

	public int getCurrentSongDuration() {
		return mCurrentSongDuration;
	}

	public int getCurrentSongPlayedTime() {
		try {
			return mMediaPlayer.getCurrentPosition();
		} catch (IllegalStateException ie) {
			return 0;
		}
	}

	public void setSavedCurrentDuration(int cur) {
		this.mSavedCurrentDuration = cur;
	}

	public int getSavedCurrentDuration() {
		return mSavedCurrentDuration;
	}

	public int getCurrentSongIndex() {
		if (mSongList.size() <= 0)
			return -1;
		return mCurrentSongIndex;
	}

	public void setCurrentSongIndex(int index) {
		this.mTempCurrentSongIndex = index;
		mCurrentSongIndex = mTempCurrentSongIndex;
	}

	public void setSkinChanged(boolean val) {
		this.mIsSkinChanged = val;
	}

	public boolean isSkinChanged() {
		return this.mIsSkinChanged;
	}

	public void setNeedUpdateAlbumArt(boolean val) {
		this.mIsNeedUpdateAlbumArt = val;
	}

	public boolean isNeedUpdateAlbumArt() {
		return this.mIsNeedUpdateAlbumArt;
	}

	public boolean IsShuffle() {
		return mIsShuffle;
	}

	public void setShuffle(boolean shuffle) {
		this.mIsShuffle = shuffle;
	}

	public void setRepeatMode(RepeatMode mode) {
		this.mRepeatMode = mode;
	}

	public RepeatMode getRepeatMode() {
		if (mRepeatMode == null)
			mRepeatMode = RepeatMode.NONE;
		return mRepeatMode;
	}

	public void setFavorite(boolean fav) {
		if (getCurrentSong() != null)
			getCurrentSong().setFavorite(fav);
	}

	public boolean isSongFavorite() {
		if (getCurrentSong() != null)
			return getCurrentSong().isFavorite();
		return false;
	}

	public int getAudioSessionId() {
		if (mMediaPlayer != null)
			return mMediaPlayer.getAudioSessionId();
		return -1;
	}

	public int getCurrentSongEffectId() {
		if (mSongList != null && mSongList.size() > 0)
			return mSongList.get(mCurrentSongIndex).getEffectId();
		return -1;
	}

	public List<Integer> getSongIds() {
		List<Integer> re = new ArrayList<Integer>();
		if (mSongList == null)
			return re;
		for (Song s : mSongList) {
			re.add(s.getId());
		}
		return re;
	}

	public void updateEffectIdForSong(int songId, int efId) {
		for (Song s : mSongList) {
			if (songId == s.getId()) {
				s.setEffectId(efId);
			}
		}
	}

	public void updateEffectIdForSongs(List<Integer> songIds, int efId) {
		for (Integer sI : songIds) {

			for (Song s : mSongList) {
				if (sI.equals(s.getId())) {
					s.setEffectId(efId);
					break;
				}
			}
		}
	}

	public MediaPlayer getMediaPlayer() {
		return mMediaPlayer;
	}

	public boolean isEqEnabled() {
		return mIsSoundEqualizer;
	}

	public void setEqEnabled(boolean eq) {
		this.mIsSoundEqualizer = eq;
	}

	public boolean isBassboostEnabled() {
		return mIsSoundBassBooster;
	}

	public void setBassboostEnabled(boolean bass) {
		this.mIsSoundBassBooster = bass;
	}

	public void notifySkinReleased(boolean val) {
		this.mIsSkinReleased = val;
	}

	@Override
	public boolean onUnbind(Intent intent) {
		Log.d("Service", "Unbind Called");
		return false;
	}

	@Override
	public void onRebind(Intent intent) {
		super.onRebind(intent);
		sendBroadcast(mSongIndexIntent);
	}

	@SuppressWarnings("deprecation")
	@Override
	public void onDestroy() {
		Log.d("Service", "Destroy Called");
		super.onDestroy();
		if (mBroadcastPlaylistChanged != null)
			unregisterReceiver(mBroadcastPlaylistChanged);
		if (mBroadcastSettingChanged != null)
			unregisterReceiver(mBroadcastSettingChanged);
		if (mBroadcastSkinChanged != null)
			unregisterReceiver(mBroadcastSkinChanged);
		if (mBroadcastHeadPhonePlugged != null)
			unregisterReceiver(mBroadcastHeadPhonePlugged);
		if (mBroadcastLockScreenChanged != null)
			unregisterReceiver(mBroadcastLockScreenChanged);
		if (mTelephonyManager != null)
			mTelephonyManager.listen(mPhoneStateListener,
					PhoneStateListener.LISTEN_NONE);
		if (mLockScreenBroadcastReceiver != null)
			unregisterReceiver(mLockScreenBroadcastReceiver);
		// if (mBroadcastHeadPhoneClick != null)
		// unregisterReceiver(mBroadcastHeadPhoneClick);
		if (isPlaying()) {
			updateWidget(false);
			saveLockScreenSetting(false);
		}
		// renebaled lockscreen
		if (keyguardLock != null)
			keyguardLock.reenableKeyguard();
		isServiceStartedByMainActivity = false;
		mHandle.removeCallbacks(updateUIRunnable);
		savePlayerSetting();
		mNotificationManager.cancelAll();
		AudioEffectManager.release();
		ThemeManager.release(ThemeManager.PLAYER_SERVICE);
		mIsSkinReleased = true;
		if (mMediaPlayer != null)
			mMediaPlayer.release();
		if (mNotificationReceiver != null)
			unregisterReceiver(mNotificationReceiver);
		SharedPreferences.Editor ed = getSharedPreferences(
				Common.SP_CONFIG_NAME, Context.MODE_PRIVATE).edit();
		ed.putBoolean(Common.SP_CONFIG_IS_LOADED, false);
		ed.commit();
		// close db
		DataBaseAccess.closeDatabase();
	}

	public void savePlayerSetting() {
		if (mSongList == null || mSongList.size() <= 0)
			return;
		// PlayerSetting ps = new PlayerSetting();
		// ps.setPlayingSongId(getCurrentSong().getId());
		// ps.setPlayingSongIndex(mCurrentSongIndex);
		// ps.setCurrentDuration(mMediaPlayer.getCurrentPosition());
		// ps.setRepeatMode(getRepeatMode());
		// ps.setShuffle(IsShuffle());
		// LaisimConfig.isEqEnable = AudioEffectManager.equalizer.getEnabled();
		// LaisimConfig.isBassEnable =
		// AudioEffectManager.bassBoost.getEnabled();
		LaisimConfig.isShuffle = IsShuffle();
		LaisimConfig.repeatMode = getRepeatMode();

		LaisimConfig.playingSongIndex = mCurrentSongIndex;
		if (mCurrentSongIndex >= 0) {
			LaisimConfig.currentDuration = mMediaPlayer.getCurrentPosition();
			LaisimConfig.playingSongId = getCurrentSong().getId();
		} else {
			LaisimConfig.currentDuration = 0;
			LaisimConfig.playingSongId = -1;
		}
		new ConfigSaverTask(getApplicationContext()).execute();
	}

	// private PlayerSetting loadPlayerSetting() {
	// PlayerSetting ps = new PlayerSetting();
	// try {
	// FileInputStream fis = getApplicationContext().openFileInput(
	// Common.PLAYER_SETTING_NAME);
	// ObjectInputStream ois = new ObjectInputStream(fis);
	// ps = (PlayerSetting) ois.readObject();
	// ois.close();
	// fis.close();
	// } catch (FileNotFoundException e) {
	// e.printStackTrace();
	// } catch (StreamCorruptedException e) {
	// // TODO Auto-generated catch block
	// e.printStackTrace();
	// } catch (IOException e) {
	// // TODO Auto-generated catch block
	// e.printStackTrace();
	// } catch (ClassNotFoundException e) {
	// // TODO Auto-generated catch block
	// e.printStackTrace();
	// }
	// return ps;
	// }

	private void saveLockScreenSetting(boolean isShow) {
		// save setting
		SharedPreferences sp = getSharedPreferences(
				Common.SP_LOCK_SCREEN_SETTING_NAME, Context.MODE_PRIVATE);
		SharedPreferences.Editor ed = sp.edit();
		ed.putBoolean(Common.SP_LOCK_SCREEN_SETTING_SHOULD_SHOW_LOCK, isShow);
		ed.commit();
		disableSystemLockScreen(isShow);
	}

	@SuppressWarnings("deprecation")
	private KeyguardManager.KeyguardLock keyguardLock;

	@SuppressWarnings("deprecation")
	private void disableSystemLockScreen(boolean disable) {
		SharedPreferences sp = getSharedPreferences(
				Common.SP_LOCK_SCREEN_SETTING_NAME, Context.MODE_PRIVATE);
		boolean useLaisimLock = sp.getBoolean(
				Common.SP_LOCK_SCREEN_SETTING_USE_LAISIM_LOCK, true);
		if (useLaisimLock) {
			if (disable) {
				keyguardLock.disableKeyguard();
			} else {
				keyguardLock.reenableKeyguard();
			}
		} else {
			keyguardLock.reenableKeyguard();
		}
	}

	private void applyPlayerSetting() {

		setCurrentSongIndex(LaisimConfig.playingSongIndex);
		setRepeatMode(LaisimConfig.repeatMode);
		setShuffle(LaisimConfig.isShuffle);
		setSavedCurrentDuration(LaisimConfig.currentDuration);
		SharedPreferences sp = getSharedPreferences(
				Common.SP_AUDIO_SETTING_NAME, Context.MODE_PRIVATE);
		mIsSoundFading = sp.getBoolean(Common.SP_AUDIO_IS_FADE, true);
		mFadeTime = sp.getInt(Common.SP_AUDIO_FADE_TIME, 1000);
	}

	private List<Song> loadSongListFromDB() {
		List<Song> songs = new ArrayList<Song>();
		mDatabase = DataBaseAccess.getInstance(getApplicationContext());
		songs = mDatabase.getAllSong();
		// update lib index to all song
		SharedPreferences sP = getSharedPreferences(Common.SP_LIBRARY_NAME,
				Context.MODE_PRIVATE);
		SharedPreferences.Editor ed = sP.edit();
		ed.putInt(Common.SP_LIBRARY_PLAYING_LIB_INDEX, 2);
		ed.putInt(Common.SP_LIBRARY_PLAYING_SONG_INDEX, 0);
		ed.commit();
		return songs;
	}

	private List<Song> loadPlayingSongListFromDB() {
		mDatabase = DataBaseAccess.getInstance(getApplicationContext());
		List<Song> songs = mDatabase.getSavedPlayingSong();
		if (songs == null || songs.size() <= 0)
			return loadSongListFromDB();
		return songs;
	}

	@Override
	public boolean onError(MediaPlayer mp, int what, int extra) {
		Log.d("Media", "Errrrrrrrrrrr");
		return false;
	}

	private void loadConfig() {
		Log.d("Service", "Load config called");
		// load config
		SharedPreferences sp = getSharedPreferences(Common.SP_CONFIG_NAME,
				Context.MODE_PRIVATE);

		LaisimConfig.isEqEnable = sp.getBoolean(Common.SP_CONFIG_EQ, false);
		LaisimConfig.isBassEnable = sp.getBoolean(Common.SP_CONFIG_BASS, false);
		LaisimConfig.isShuffle = sp.getBoolean(Common.SP_CONFIG_SHUFFLE, false);
		int rePepeat = sp.getInt(Common.SP_CONFIG_REPEAT, 0);
		RepeatMode reP = rePepeat == 0 ? RepeatMode.NONE
				: (rePepeat == 1 ? RepeatMode.REPEAT_ONE
						: RepeatMode.REPEAT_ALL);
		LaisimConfig.repeatMode = reP;
		LaisimConfig.playingSongId = sp
				.getInt(Common.SP_CONFIG_PLAY_SONG_ID, 0);
		LaisimConfig.playingSongIndex = sp.getInt(
				Common.SP_CONFIG_PLAY_SONG_INDEX, 0);
		LaisimConfig.currentDuration = sp.getInt(
				Common.SP_CONFIG_CURRENT_DURATION, 0);
	}

	@SuppressLint("NewApi")
	@Override
	public void onTaskRemoved(Intent rootIntent) {
		// super.onTaskRemoved(rootIntent);
		// if(!mMediaPlayer.isPlaying())
		// play();
		// displayNotification(true);
		if (isPlaying()) {
			// update notifi to launch welcomac

		}
		// starts
		Log.e("ontask remove", "akjnfosaf" + isPlaying() + ",live: ");
	}
}
